Action: Assignment Submission - Connecting the Frontend to the Backend
Last updated: Feb 3rd, 2024
Description
Here’s what your assignment for this section was.
Build and connect a UI to the existing backend which enables a user to perform the following use case/user experience: Starting from the main page, a user should immediately see the top rated posts in DDDForum. The then user clicks the registration button in the menu, taking them to the registration page. From the registration page, the user enters their firstName, lastName, email & username to create an account. Upon success, they should see a success toast appear, and after 3 seconds, they should be redirected to the main page again. Their username should be present in the menu signalling that they’re logged in.
Pre-requisites
To get to this assignment milestone, you'll want to ensure you've gone through the previous lessons in this section and can confirm that:
- You know how to translate screens into data, behaviour & namespace requirements across the frontend, backend & database
- You can build out basic screens & functionality using any UI library
- You know how to use state management solutions (such as Redux or React Context) to cache frontend data globally
- You know how to use Axios, Fetch, or any networking library to communicate w/ a Backend API
- You know how to write migrations & seed scripts to adjust your database structure and data over time
- You know how to write queries that join data across tables using your ORM of choice
- (optionally) You know how to use ChatGPT and how to ask it to generate server code and scripts
- (optionally) You know how to use Socratic Questioning to learn the specifics of any tool or technology (such as databases, ORMs, scripting, and other Code-First concerns)
Requirements
Let’s pull up the requirements again so you have it here.
Display popular posts starting @ the Main Page
“Starting from the main page, a user should immediately see the top rated posts in DDDForum.”
That should look something like this.
Registration
“The user clicks the registration button in the menu (Join), taking them to the registration page.”
You’ll want to get this registration page goin’.
Doesn’t have to look perfect.
Failure to register
If the user tries to register and it fails, then we should show a failure toast at the top right corner like so.
These failures are going to be based on the failures we’ve identified while building out the API in the first part of this assignment.
So that’s:
- EmailAlreadyTaken
- UsernameAlreadyTaken
- InvalidUserInput
Successful submission & redirect
“From the registration page, the user enters their firstName, lastName, email & username to create an account.”
“Upon success, they should see a success toast appear, and after 3 seconds, they should be redirected to the main page again.”
That’ll look like this.
And when you get redirected to the main page after a few seconds, you should be able to see the username that you’ve used to register.
Requirements summary
In summary, the requirements are:
- start on the main page (”/”)
- should show a list of posts
- click on “sign up” or “join” button
- takes you to “/register” or “/registration”
- registration (”/registration”) page
- should allow you to register with (firstName, lastName, email, username)
- click submit
- (optional) loading spinner shows
- if failure, shows a failure toast
- if success, shows a success toast and takes you back to main after 3 seconds
- main page again (”/”)
- should show your username in the panel
And of course, this should all work front to back.
Steps: How to complete this assignment
Here are the steps you’ll need to walk through to complete the assignment.
Step 1: Review the screens to understand new data & behaviour requirements
In the starting project, we were just building a backend API.
Now, we’re adding a frontend.
Therefore, it should be clear that we’re going to need to:
- introduce a frontend folder
- install some dependencies to the frontend
- make some changes to the backend
- make some changes to the database
- make sure that the frontend can talk to the backend
Let’s quickly review what we’ll need.
Frontend: In terms of the abstraction layers you’ll need to get this to work on the frontend, you’ll need:
-
a state management solution — I’m using react context for this.
-
a routing solution — I’m using react-router for this.
-
a networking solution — I’m using axios for this.
-
an approach to handling styling — I’m just using pure css.
-
a ui library — I’m using react w/ typescript. I’m also using vite to set it up.
-
a notification/Toast library — I’m using react-toast instead of building it out myself.
Backend: In terms of the backend API abstraction layer, what changes?
-
api layer — you'll need a new api endpoint via /posts
-
api middleware layer — you’re going to need to use CORS to enable the frontend to make API calls to the backend.
-
database structure — you’ll need to adjust your database schema. this is relatively easy to change if you’re using an ORM like prisma.
-
migrations — you’ll need to introduce a migration file to actually change the database structure. then you’ll need to run it.
-
seeder — finally, there’s the need for a seeder
-
scripting — and the layer which actually does all of the work to run the migrations and run the seeder file? Yes, of course, from a horizontal decoupling POV, that’s the scripting layer. so you’ll have to tinker with this a little bit as well. you’ll want your migrations to run before you start the app & you’ll want your seed data to apply as well.
Database: Finally, at the database layer, you’ll notice the following data model changes:
- a new Posts data model
- a Post has 0 or more Comments
- a Post has at least one Vote, which will initially be an upvote
- a Vote belongs to a Member
- a Member is a User
- So we have
- Post
- Comment
- Member
- Vote
That’s what’s most important to note. You can use your common sense to infer the properties.
Step 2: Setup frontend project & install new dependencies
Next, let’s get setup with the project
You can use Vite to setup a new React TypeScript project. Pretty nifty tool. 10x better than how I used to do this in the past.
Then you’ll want to install all the new frontend dependencies:
npm install axios react-router-dom react-toastify
Step 3: Build the layout, presentational components
Once you’ve got the frontend & backend folders setup, dependencies going, go ahead and get the layouts and components built out using the popular “component-first approach”.
If you’ve built frontends before, this should feel pretty much like breathing to you at this point.
Note: While some developers don’t like to make any distinctions about the pages and presentational components, I prefer to designate a folder specifically for pages. That’s part of my philosophy of how to organize things, which will make more sense in Best Practice-First, but do it however you like. Just a suggestion. You can always take a look at how I’ve done it here.
Step 4: Build the frontend registration logic
After you’ve got the layout and all of the components setup, start thinking about the registration logic. A few things need to happen.
- Form State. You’re going to need to get the form state saved somewhere. Typically, I call this local state. You can use something like useState to handle this with React.
- Validation. Then you’ll need to validate that stuff onSubmit, so you’ll need a place to handle that, and if there’s a failure, you’ll want to show the error toast.
While you’re implementing the logic, don’t worry too much about if it’s “in the right place” or not. Just make it work. Flow with it, re-arrange and move things around.
When you get to Pattern-First, you’ll have a much more clear understanding of what belongs where…
But simplicity first. This technique works quite well.
- Registration (Interaction) Logic. Of course, we’ve also got to make the API call, handle the response, present the error or success message, save the response data to local state, and redirect to the main page after 3 seconds if it was successful.
Pretty standard stuff, right? You’ve got this.
Read the requirements again if you need to clarify the behaviour.
Step 5: Design the new structure of the database
Registration working? All good.
Next thing we’ll have to do is update the database schema based on these new data models changes.
Now, depending on the way you’ve set up your database and your application server, it’ll differ.
For me, because I’m using Prisma, it’s going to be pretty straightforward. All I have to do is update the schema file.
To adjust the database, you’ll need to understand a bit about relationships & cardinality.
For example, there’s the concept of the Post, and a Post can have 0 or more Comments. How do you model that in a Prisma schema file? What does that translate to at the database level?
I’ll leave you to figure that out — it’ll also be different depending on the tool you’re using, of course.
If you’re really stuck, you can take a look at how I’ve done it here or ask questions #course-chat. If y’all really get stuck here, I’ll throw in a lesson for you.
FAQ: “What’s the purpose of having a user and a member table/data model? They seem like they’re the same thing, aren’t they?”
We’re not quite there yet, but this is taking us into Domain-Driven Design territory with the idea of Bounded Contexts and the like. Simply speaking, it is good practice to separate the concept of a User from that of the various types of roles a user can play.
A user might exist as the data model which handles the behaviour of auth, password management, account verification, and so on.. Where a member might exist to handle the responsibilities of posting, commenting, voting and so on.
Definitely want to avoid the rabbit hole this early on, but have a think about this if you haven’t encountered it before.
Step 6: Create a database migration to update the database structure
Once I’ve made the changes to my schema file, I’ll need to push the changes to the database.
Again, if you’re using raw SQL or some other ORM like Sequelize, this could be slightly different, but something that will always be the same is the need for a migration.
Because I’m using Prisma, I can first use the prisma migrate command to get it to generate a migration file from the new schema (see the docs here).
Next, I can run prisma migrate dev to get it to run the migration, changing the database structure, and generating the new data model types for use in development.
Step 7: Write seeder scripts to load the database w/ initial data
Migrations done. Database updated, cool.
But what about the data? Part of the requirements are to display data from the backend.
That means we’ll need to seed the database with some data ahead of time.
You’ll want to write a seeder script. If you’re using Prisma, here are some docs you can use to make sense of this.
You can also take a look at how I’ve done this myself.
How much data should you seed? Take a look at the requirements and try to create a similar amount of data. At least 3 posts with variance on the votes and comments.
Step 8: Build & connect the posts API to the frontend
We’re almost done. Next, we’ll need to create the posts api to return the seeder data we just created in the database.
You should know generally by now how to use your ORM to fetch data from the database AND you should know how to make new API endpoints.
But you might not know how to perform database joins using the ORM.
Your task here is to return enough data in a single API call to show all of the popular posts data on screen. This means you’ll need to join across a few different database tables.
Here’s an example of the shape of the response data.
{"data":{"posts":[{"id":1,"memberId":1,"postType":"Text","title":"First post!","content":"This is bob vances first post","dateCreated":"2023-11-25T03:53:58.786Z","votes":[{"id":1,"postId":1,"memberId":1,"voteType":"Upvote"}],"memberPostedBy":{"id":1,"userId":1,"user":{"id":1,"email":"bobvance@gmail.com","firstName":"Bob","lastName":"Vance","username":"bobvance","password":"123"}},"comments":[{"id":1,"postId":1,"text":"I posted this!","memberId":1,"parentCommentId":null}]},{"id":2,"memberId":1,"postType":"Text","title":"Second post!","content":"This is bobs second post","dateCreated":"2023-11-25T03:53:58.786Z","votes":[{"id":2,"postId":2,"memberId":1,"voteType":"Upvote"},{"id":6,"postId":2,"memberId":3,"voteType":"Downvote"}],"memberPostedBy":{"id":1,"userId":1,"user":{"id":1,"email":"bobvance@gmail.com","firstName":"Bob","lastName":"Vance","username":"bobvance","password":"123"}},"comments":[{"id":2,"postId":2,"text":"Nice","memberId":2,"parentCommentId":null}]},{"id":3,"memberId":2,"postType":"Text","title":"another post","content":"This is tonys first post","dateCreated":"2023-11-25T03:53:58.786Z","votes":[{"id":3,"postId":3,"memberId":2,"voteType":"Upvote"},{"id":5,"postId":3,"memberId":1,"voteType":"Upvote"}],"memberPostedBy":{"id":2,"userId":2,"user":{"id":2,"email":"tonysoprano@gmail.com","firstName":"Tony","lastName":"Soprano","username":"tonysoprano","password":"123"}},"comments":[]},{"id":4,"memberId":2,"postType":"<https://khalilstemmler.com>","title":"Links","content":"This is a link post","dateCreated":"2023-11-25T03:53:58.786Z","votes":[{"id":4,"postId":4,"memberId":2,"voteType":"Upvote"}],"memberPostedBy":{"id":2,"userId":2,"user":{"id":2,"email":"tonysoprano@gmail.com","firstName":"Tony","lastName":"Soprano","username":"tonysoprano","password":"123"}},"comments":[]}]},"success":true}
Ultimately, the structure of the join is:
- post to votes, member, and comments
- and member to user
“Uhhh, this is gonna be an expensive query”! Ah, you’re sharp. Yes, this could potentially become a very expensive query moving forward. But again, let’s get this working first. We’ll remedy this in Pattern-First with better patterns and techniques to think about this.
Get this going, hook it up to an API endpoint at /posts?sort=recent and connect it to the frontend. Don’t forget to use cors.
Step 9: Test it out
By this point, we should have everything working as intended.
Give it all a test manually while looking through the Grading Checklist.
Great work!
How to know when you’re finished
Use the following grading checklist to self-evaluate (and evaluate others' assignment submissions) to see the assignment has been done correctly.
Grading Checklist
Backend
-
🔘 I have built a getPopularPosts API which returns return the data in the following or similar shape
-
/posts?sort=recent: Gets posts sorted by popularity
-
Example response data:
{"data":{"posts":[{"id":1,"memberId":1,"postType":"Text","title":"First post!","content":"This is bob vances first post","dateCreated":"2023-11-25T03:53:58.786Z","votes":[{"id":1,"postId":1,"memberId":1,"voteType":"Upvote"}],"memberPostedBy":{"id":1,"userId":1,"user":{"id":1,"email":"bobvance@gmail.com","firstName":"Bob","lastName":"Vance","username":"bobvance","password":"123"}},"comments":[{"id":1,"postId":1,"text":"I posted this!","memberId":1,"parentCommentId":null}]},{"id":2,"memberId":1,"postType":"Text","title":"Second post!","content":"This is bobs second post","dateCreated":"2023-11-25T03:53:58.786Z","votes":[{"id":2,"postId":2,"memberId":1,"voteType":"Upvote"},{"id":6,"postId":2,"memberId":3,"voteType":"Downvote"}],"memberPostedBy":{"id":1,"userId":1,"user":{"id":1,"email":"bobvance@gmail.com","firstName":"Bob","lastName":"Vance","username":"bobvance","password":"123"}},"comments":[{"id":2,"postId":2,"text":"Nice","memberId":2,"parentCommentId":null}]},{"id":3,"memberId":2,"postType":"Text","title":"another post","content":"This is tonys first post","dateCreated":"2023-11-25T03:53:58.786Z","votes":[{"id":3,"postId":3,"memberId":2,"voteType":"Upvote"},{"id":5,"postId":3,"memberId":1,"voteType":"Upvote"}],"memberPostedBy":{"id":2,"userId":2,"user":{"id":2,"email":"tonysoprano@gmail.com","firstName":"Tony","lastName":"Soprano","username":"tonysoprano","password":"123"}},"comments":[]},{"id":4,"memberId":2,"postType":"<https://khalilstemmler.com>","title":"Links","content":"This is a link post","dateCreated":"2023-11-25T03:53:58.786Z","votes":[{"id":4,"postId":4,"memberId":2,"voteType":"Upvote"}],"memberPostedBy":{"id":2,"userId":2,"user":{"id":2,"email":"tonysoprano@gmail.com","firstName":"Tony","lastName":"Soprano","username":"tonysoprano","password":"123"}},"comments":[]}]},"success":true}
-
-
🔘 I have seeded the database with enough initial data to fulfill a similar view when getPopularPosts is called
- at least 3 posts
- at least 2 posts have comments
- all posts have votes
Frontend
View
- 🔘 I have built the UI using any UI library to which looks similar to the screens from the requirements
Main
- 🔘 When the page loads at “/”, I should see a list of posts retrieved from the backend API
Registration
- 🔘 When I successfully register at @ “/register”, according to the requirements, I should be presented w/ a success toast before being redirected to the “/” page
- 🔘 (Failure case) When I enter invalid account details, I should see a failure Toast
- 🔘 (Failure case) When I register with an already created username, I should see a failure Toast
- 🔘 (Failure case) When I register with an already taken email, I should see an error presented in a failure toast
- 🔘 (Success case) When I successfully register and am redirected, I should see the username in the menu </aside>
Previous submissions
You’ll be able to find a demonstration, the instructor submission & submissions from your classmates here.
Instructor demonstration
- Not yet posted
My solution
And you can see submissions from your classmates below:
- None completed yet! submit yours to be the first
When you’re finished
Finally, when you're satisfied with your implementation, submit your assignment.
Here's how (you can also watch the video here).
- Push your new branch to GitHub using git push -u origin <branchName>
- Go to GitHub, create a PR & copy the link
- Submit your assignment as a new post within the forum using the PR link
2. Review at least 1 other solution
You can watch this video here to learn how to review assignments.
3. (Optional) Discuss in #course-chat
How'd you enjoy this one? Want to talk about it? Still have questions? Get stuck? Jump into #course-chat and join the discussion.
Need help?
Use #course-chat for help
If you're struggling to implement a particular deliverable or have a question about one, feel free to ask in #course-chat.
—
Want to help me improve this assignment?
Leave any important questions or suggestions below.
As always,
To Mastery.





